<?php


namespace App\Repositories;


use App\Http\Requests\Customer\Product\Index\StoreRequest;
use App\Models\Product as ProductModel;
use App\Models\ProductImport as Model;
use App\Traits\Logs;
use Exception;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use LTools\Repositories\RepositoryAbstract;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class ProductImport extends RepositoryAbstract
{
    /**
     * ProductImport constructor.
     * @param Model $model
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    public function paginate(array $attributes, int $perPage = null, array $columns = ['*'], $pageName = 'page', int $page = null)
    {
        return $this->model->with(['user'])->where(
            $attributes
        )->paginate($perPage, $columns, $pageName, $page);
    }

    /**
     * @param array $attributes
     * @return bool|\Illuminate\Database\Eloquent\Model
     * @throws ValidationException
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public function create(array $attributes = [])
    {
        $attributes['user_id'] = auth()->user()->getKey();
        /** @var Model $model */
        $model = parent::create($attributes);
        // 导入模板
        $this->import($model);
        return $model;
    }


    /**
     * @param Model $model
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws ValidationException
     * @throws Exception
     */
    protected function import($model)
    {

        $file = public_path($model->getAttribute('file'));
        $reader = new Xlsx();
        $spreadsheet = $reader->load($file);
        $worksheet = $spreadsheet->getSheet(0);


        switch ($model->getAttribute("type")) {
            case 0:
                $this->checkingProductExcel($worksheet);
                //
                foreach ($this->getImportProduct($worksheet) as $product) {
                    $this->importProduct(
                        array_merge($product, ['customer_id' => $model->getAttribute('customer_id')])
                    );
                }
                break;
            case 1:
                $hsCode = $this->checkingModelExcel($worksheet);
                $this->importModel($worksheet, $hsCode);
        }
    }


    /**
     * @param array $attributes
     * @throws ValidationException
     */
    protected function importProduct(array $attributes)
    {
        /** @var Product $product */
        $productReps = app(Product::class);
        $request = new StoreRequest();
        $rules = $request->commonRules();

        $validator = Validator::make(
            $attributes,
            $rules
        );
        if ($validator->fails()) {
            throw new ValidationException($validator);
        }
        $productReps->create($attributes);
    }

    /**
     * @param Worksheet $worksheet
     * @param \App\Models\HsCode $code
     * @throws Exception
     */
    protected function importModel(Worksheet $worksheet, \App\Models\HsCode $code)
    {
        $rowIterator = $worksheet->getRowIterator(2);

        $elementCount = count($code->getAttribute('element'));

        $request = new StoreRequest();
        $rules = $request->elementRules($code->getAttribute('code'));


        foreach ($rowIterator as $iterator) {
            $sku = $iterator->getCellIterator('A', 'A')->current()->getValue();

            try {
                /** @var ProductModel $product */
                $product = ProductModel::query()
                    ->where('sku', '=', $sku)
                    ->where('status', '=', 0)
                    ->where('hs_code', '=', $worksheet->getTitle())
                    ->where('customer_id', '=', request()->input('customer_id'))
                    ->lockForUpdate()->firstOrFail();

                // 上传完申报要素模板产品就更新成审核状态
                $productUpdate = ['element' => [], 'qy1' => '', 'qy2' => '', 'status' => 1];

                $index = 0;
                foreach ($iterator->getCellIterator('B') as $item) {
                    if ($index < $elementCount) {
                        $productUpdate['element'][$index] = $item->getValue();
                    } else if ($index === $elementCount) {
                        $productUpdate['qy1'] = $item->getValue();
                    } else if ($index === $elementCount + 1) {
                        $productUpdate['qy2'] = $item->getValue();
                    }
                    $index++;
                }
                // array to string
                $productUpdate['element'] = implode('|', $productUpdate['element']);

                // 验证
                $validator = Validator::make(
                    $productUpdate,
                    $rules
                );
                if ($validator->fails()) {
                    throw new ValidationException($validator);
                }

                $product->update($productUpdate);

            } catch (ValidationException $exception){
                throw $exception;
            }catch (Exception $exception) {
                throw new Exception(sprintf("找不到sku为[%s]的产品或者产品不是草稿状态： %s", $sku, $exception->getMessage()));
            }


        }
    }


    /**
     * @param Worksheet $worksheet
     * @return \Generator
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    protected
    function getImportProduct(Worksheet $worksheet)
    {
        $rowIterator = $worksheet->getRowIterator(3);
        $transform = ['sku', 'barcode', 'name', 'net_weight', 'weight', 'brand', 'hs_code', 'country', 'unit', 'currency', 'model', 'specs', 'function', 'use', 'ingredient'];
        $rowArray = [];
        foreach ($rowIterator as $iterator) {
            foreach ($iterator->getCellIterator('A', 'O') as $index => $item) {
                $rowArray[$transform[Coordinate::columnIndexFromString($index) - 1]] = $item->getValue();
            }
            yield $rowArray;
        }
    }


    /**
     * @param Worksheet $worksheet
     * @throws Exception
     */
    protected
    function checkingProductExcel(Worksheet $worksheet)
    {
        $titleRow = $worksheet->getRowIterator(2, 2)->current();
        $signStr = "产品SKU默认条码产品名称产品净重产品毛重品牌商品编码原产国申报单位申报币种型号规格功能用途成分";
        $titleStr = '';
        foreach ($titleRow->getCellIterator('A', 'O') as $index => $item) {
            $titleStr .= $item->getFormattedValue();
        }
        if (trim($signStr) !== trim($titleStr)) {
            throw new Exception("产品模板验证不通过！请不要更改模板表头！");
        }
    }


    /**
     * @param Worksheet $worksheet
     * @return \App\Models\HsCode
     * @throws Exception
     */
    protected
    function checkingModelExcel(Worksheet $worksheet)
    {
        /** @var HsCode $hsCode */
        $hsCode = app(HsCode::class);
        try{
            /** @var \App\Models\HsCode $model */
            $model = $hsCode->find($worksheet->getTitle());
        }catch (Exception $exception){
            throw new Exception('请不要更改模板表头和sheet名称！');
        }


        $headers = $hsCode->templateHeaders($model);

        $signStr = implode('', $headers);

        $titleRow = $worksheet->getRowIterator(1, 1)->current();
        $titleStr = '';
        foreach ($titleRow->getCellIterator() as $index => $item) {
            $titleStr .= $item->getFormattedValue();
        }
        if (trim($signStr) !== trim($titleStr)) {
            throw new Exception("申报要表模板验证不通过！");
        }

        return $model;
    }
}
